﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Caching;
using Medianamik.Core.Caching;
using Medianamik.Core.DAL.Services;
using Medianamik.Core.Interfaces;
using SubSonic;

namespace Medianamik.Core.DAL.Repositories
{
    public class CachedMedianamikRepository<TCollection, TItem, TRepository> :
        IMedianamikRepository<TItem>
        where TRepository : IMedianamikRepository<TItem>
        where TCollection : ICollectionWithChildren<TCollection, TItem>, new()
        where TItem : IMedianamikDTO, IRecordBase, new()
    {
        private const string ChildsKey = " Childs Of ";
        private const string ParentsKey = " Parents Of ";

        private readonly TRepository _repository;
        private readonly ICacheService<TItem> _cache;

        private readonly Func<CacheDependency> _getDependency;

        public CachedMedianamikRepository(TRepository repository,
                                          ICacheService<TItem> cache, Func<CacheDependency> getDependency)
        {
            _repository = repository;
            _cache = cache;
            _getDependency = getDependency;
        }

        protected CacheDependency GetCacheDependency
        {
            get { return _getDependency.Invoke(); }
        }

        protected ICacheService<TItem> CacheService
        {
            get { return _cache; }
        }

        protected TRepository Repository
        {
            get { return _repository; }
        }

        public TItem Get(Guid nodeId)
        {
            throw new NotImplementedException();
        }

        public virtual TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState)
        {
            var key = nodeId + culture.Name + contentState.ToString("F");

            return _cache.Get(key, _getDependency(), () => Repository.Get(nodeId, culture, contentState));
        }

        public TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, ActiveStatus activeStatus)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> GetWithFilters(Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
                                           IEnumerable<BetweenAnd> betweensAnd, string orderByString, int? depth,
                                           bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public PagedCollection<TItem> PagedWithFilters(int pageIndex, int pageSize, Guid? typeId, Guid? parentId,
                                                       IEnumerable<Where> wheres, IEnumerable<BetweenAnd> betweensAnd,
                                                       string orderByString, int? depth, bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<TItem> LoadByIDs(string ids)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<TItem> LoadByIDs(IList<Guid> ids)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> All()
        {
            throw new NotImplementedException();
        }

        public virtual TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState, TimeSpan slidingExpiration)
        {
            var key = nodeId + culture.Name + contentState.ToString("F");

            return _cache.Get(key, slidingExpiration, _getDependency(),
                              () => Repository.Get(nodeId, culture, contentState));
        }

        public virtual TItem Get(Guid nodeId, CultureInfo culture, ContentState contentState,
                                 DateTime absoluteExpiration)
        {
            var key = nodeId + culture.Name + contentState.ToString("F");

            return _cache.Get(key, absoluteExpiration, _getDependency(),
                              () => Repository.Get(nodeId, culture, contentState));
        }

        public IList<TItem> GetWithFilters(CultureInfo culture,
                                           ContentState contentState, ActiveStatus status, Guid? typeId,
                                           Guid? parentId, IEnumerable<Where> wheres,
                                           IEnumerable<BetweenAnd> betweensAnd, string orderByString, int? depth,
                                           bool withTypeInheritance)
        {
            return Repository.GetWithFilters(culture, contentState, status, typeId,
                                             parentId, wheres, betweensAnd, orderByString, depth, withTypeInheritance);
        }

        public PagedCollection<TItem> PagedWithFilters(CultureInfo culture,
                                                       ContentState contentState, ActiveStatus status, int pageIndex,
                                                       int pageSize,
                                                       Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
                                                       IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                       int? depth,
                                                       bool withTypeInheritance)
        {
            return Repository.PagedWithFilters(culture, contentState, status, pageIndex,
                                               pageSize, typeId, parentId, wheres, betweensAnd, orderByString, depth,
                                               withTypeInheritance);
        }

        public PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, ContentState contentState,
                                                       ActiveStatus status, int pageIndex, int pageSize, Guid? typeId,
                                                       Guid? parentId, IEnumerable<Where> wheres,
                                                       IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                       int? depth, bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> ChildsOf(Guid nodeId, bool inclusive, int maxDepth,
                                     CultureInfo culture, ContentState contentState, ActiveStatus status)
        {
            var key = culture.Name + ChildsKey + nodeId + inclusive + maxDepth +
                      contentState.ToString("F") + status.ToString("F");
            return _cache.GetCollection(key, _getDependency(),
                                        () => Repository.ChildsOf(nodeId, inclusive, maxDepth, culture,
                                                                  contentState, status));
        }

        public IList<TItem> ParentsOf(Guid nodeId, bool inclusive, int maxDepth,
                                      CultureInfo culture, ContentState contentState, ActiveStatus status)
        {
            var key = culture.Name + ParentsKey + nodeId + inclusive + maxDepth + contentState.ToString("F") +
                      status.ToString("F");
            return _cache.GetCollection(key, _getDependency(),
                                        () => Repository.ParentsOf(nodeId, inclusive, maxDepth, culture, contentState,
                                                                   status));
        }

        public IEnumerable<TItem> LoadByIDs(string ids, string cultureName, ContentState contentState,
                                            ActiveStatus status)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<TItem> LoadByIDs(IList<Guid> ids, string cultureName, ContentState contentState,
                                            ActiveStatus status)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> All(CultureInfo culture, ContentState contentState,
                                ActiveStatus status)
        {
            return Repository.All(culture, contentState, status);
        }

        public void DeleteByParent(Guid parendId, bool destroy)
        {
            Repository.DeleteByParent(parendId, destroy);
        }

        public void DeleteBranch(Guid nodeId, bool destroy)
        {
            Repository.DeleteBranch(nodeId, destroy);
        }

        public void Delete(TItem item)
        {
            Repository.Delete(item);
        }

        #region Map And Save

        public void MapAndSaveItem<T>(T item, MappingOptions options) where T : IMedianamikDTO
        {
            Repository.MapAndSaveItem(item, options);
        }
        public void MapAndSaveItem<T>(T item) where T : IMedianamikDTO
        {
            MapAndSaveItem(item, MappingOptions.DefaultOptions);
        }

        public void MapAndSaveItems<T>(IEnumerable<T> items, MappingOptions options) where T : IMedianamikDTO
        {
            Repository.MapAndSaveItems(items, options);
        }
        public void MapAndSaveItems<T>(IEnumerable<T> items) where T : IMedianamikDTO
        {
            MapAndSaveItems(items, MappingOptions.DefaultOptions);
        }

        public void MapAndPublishItem<T>(T item, MappingOptions options) where T : IMedianamikDTO
        {
            MapAndPublishItem(item, options);
        }
        public void MapAndPublishItem<T>(T item) where T : IMedianamikDTO
        {
            MapAndPublishItem(item, MappingOptions.DefaultOptions);
        }

        public void MapAndPublishItems<T>(IEnumerable<T> items, MappingOptions options) where T : IMedianamikDTO
        {
            Repository.MapAndPublishItems(items, options);
        }
        public void MapAndPublishItems<T>(IEnumerable<T> items) where T : IMedianamikDTO
        {
            MapAndPublishItems(items, MappingOptions.DefaultOptions);
        }

        #endregion

        public void Delete(Guid nodeId, bool destroy)
        {
            Repository.Delete(nodeId, destroy);
        }

        public IList<TItem> GetWithFilters(bool multiLingual, CultureInfo culture,
                                           ActiveStatus status, Guid? typeId, Guid? parentId, DateTime? startDate,
                                           DateTime? endDate, string keywords, string orderBy,
                                           IEnumerable<Where> additionalWheres,
                                           bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AllInstances()
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AllInstances(ContentState contentState, ActiveStatus status)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AllInstances(Guid nodeId)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AllInstances(Guid nodeId, ContentState contentState, ActiveStatus status)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AlllInstancesWithFilters(ContentState contentState, ActiveStatus status, Guid? typeId,
                                                     Guid? parentId, IEnumerable<Where> wheres,
                                                     IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                     int? depth, bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public IList<TItem> AlllInstancesWithFilters(Guid? typeId, Guid? parentId, IEnumerable<Where> wheres,
                                                     IEnumerable<BetweenAnd> betweensAnd, string orderByString,
                                                     int? depth, bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public void Reorder(Guid id, Guid destinationId, DropPosition position)
        {
            Repository.Reorder(id, destinationId, position);
        }

        public PagedCollection<TItem> PagedWithFilters(CultureInfo editionCulture, int pageIndex,
                                                       int pageSize, Guid baseTypeId, Guid moduleNodeId,
                                                       IEnumerable<Where> additionalWheres)
        {
            throw new NotImplementedException();
        }

        public void SetActiveStatus(Guid id, CultureInfo culture, ActiveStatus status)
        {
            Repository.SetActiveStatus(id, culture, status);
        }

        public void SaveNodes(IEnumerable<Node> nodes)
        {
            Repository.SaveNodes(nodes);
        }

        public INodeWrapper NewNode(IMedianamikDTO dto)
        {
            return Repository.NewNode(dto);
        }

        public INodeWrapper NewNode(IMedianamikDTO dto, bool validateHierarchicalRules)
        {
            return Repository.NewNode(dto, validateHierarchicalRules);
        }

        public INodeWrapper GetExistingNode(IMedianamikDTO dto)
        {
            return Repository.GetExistingNode(dto);
        }

        public void SaveNode(INodeWrapper node)
        {
            Repository.SaveNode(node);
        }

        public void PublishNode(INodeWrapper node,
                                CultureInfo culture)
        {
            Repository.PublishNode(node, culture);
        }

        public void SaveNodeHandlingPositionAndParentNodeId(INodeWrapper node,
                                                            Guid? parentNodeId, short? position)
        {
            Repository.SaveNodeHandlingPositionAndParentNodeId(node, parentNodeId, position);
        }

        public void PublishNodeHandlingPositionAndParentNodeId(INodeWrapper node,
                                                               Guid? parentNodeId, short? position, CultureInfo culture)
        {
            Repository.PublishNodeHandlingPositionAndParentNodeId(node, parentNodeId, position, culture);
        }

        public INodeMapper NodeMapper
        {
            get { return Repository.NodeMapper; }
        }

        public ICultureService CultureService
        {
            get { return Repository.CultureService; }
        }

        public IContentStateService ContentStateService
        {
            get { return Repository.ContentStateService; }
        }

        public PagedCollection<TItem> PagedWithFilters(CultureInfo editionCulture, int pageIndex,
                                                       int pageSize, ActiveStatus contentStatus, Guid? baseTypeId,
                                                       Guid? moduleNodeId,
                                                       DateTime? startDate, DateTime? endDate, string keywords,
                                                       string orderBy,
                                                       IEnumerable<Where> additionalWheres, bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }

        public PagedCollection<TItem> PagedWithFilters(bool multiLingual, CultureInfo culture, int pageIndex,
                                                       int pageSize, ActiveStatus status, Guid? typeId, Guid? parentId,
                                                       DateTime? startDate,
                                                       DateTime? endDate, string keywords, string orderBy,
                                                       IEnumerable<Where> additionalWheres,
                                                       IEnumerable<BetweenAnd> additionalBetweenAnds,
                                                       bool withTypeInheritance)
        {
            throw new NotImplementedException();
        }
    }
}